/***************************************************************************
                          ezoutput  -  description
                             -------------------
    begin                : Oct. 17, 2004
    copyright            : (C) 2005 by Allen
    email                : bon_ami_@hotmail.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   Explicit Distribution Limitation                                      *
 *   This rule overrides others below.                                     *
 *   This program may not be modified or used by, or, if possible,         *
 *   redistributed to people described as below,                           *
 *   1.Japanese who hold hostility against Chinese.                        *
 *   2.or, those who discriminate against people based solely on race,     *
 *     gender or sexual orientation.                                       *
 *                                                                         *
 ***************************************************************************/
/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
/*
 *	header of EZ Output
 *
 *	memory output to screen(directly) or character buffer(indirectly)
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define EZOUTPUT_SUIT_WIDTH(WIDTH, COLUMN, BARRIER, OPTIONS)                   \
  do {                                                                         \
    if (OPTIONS < 0) {                                                         \
      if (WIDTH > 0) {                                                         \
        if (BARRIER > 0) {                                                     \
          if ((0 == COLUMN) ||                                                 \
              ((12 + (13 * COLUMN) + (COLUMN / BARRIER * 4)) > WIDTH))         \
            COLUMN = (WIDTH - 12) / (13 + 4 / (float)BARRIER);                 \
        } else if ((0 == COLUMN) || (COLUMN > ((WIDTH - 12) / 13)))            \
          COLUMN = (WIDTH - 12) / 13;                                          \
      } else if (COLUMN < 1)                                                   \
        COLUMN =                                                               \
            (80 - 12) / (13 + ((BARRIER > 0) ? (4 / (float)BARRIER) : 0));     \
      WIDTH =                                                                  \
          12 + (13 * COLUMN) + ((BARRIER > 0) ? (COLUMN / BARRIER * 4) : 0);   \
    } else {                                                                   \
      if (WIDTH > 0) {                                                         \
        if (BARRIER > 0) {                                                     \
          if ((0 == COLUMN) ||                                                 \
              ((10 + (4 * COLUMN) + (COLUMN / BARRIER * 2)) > WIDTH))          \
            COLUMN = (WIDTH - 10) / (4 + 2 / (float)BARRIER);                  \
        } else if ((0 == COLUMN) || (COLUMN > ((WIDTH - 10) / 4)))             \
          COLUMN = (WIDTH - 10) / 4;                                           \
      } else if (COLUMN < 1)                                                   \
        COLUMN = (80 - 10) / (4 + ((BARRIER > 0) ? (2 / (float)BARRIER) : 0)); \
      WIDTH =                                                                  \
          10 + (4 * COLUMN) + ((BARRIER > 0) ? (COLUMN / BARRIER * 2) : 0);    \
    }                                                                          \
  } while (0)

/*
DISP: char*, ouput space allocated inside if successful
MODULE: char*, must not be NULL, header for output. you may want to include
  __FILE__ & __LINE__ as parts of it
BUF: char*, input memory address
SIZE: int, input memory size, 0-65535
WIDTHS: screen width. auto-shrink if larger than COLUMN
       0: unlimited if COLUMN not defined either, default to 80
COLUMNS: column(group) count in a line. auto-shrink if display result larger
  than WIDTH
       0: unlimited
BARRIER: show | at every these columns. must not be 0
OPTIONS: signed integer(char, short, int or long)
       yes:  no:  functionality:
       odd  even  compress blank lines
       <0  >=0  display binary
*/
#define EZOUTPUT_I(DISP, MODULE, BUF, SIZE, WIDTHS, COLUMNS, BARRIER, OPTIONS) \
  do {                                                                         \
    unsigned int EZOUTPUT_I_I;                                                 \
    unsigned int EZOUTPUT_I_J;                                                 \
    char EZOUTPUT_I_K;                                                         \
    unsigned char EZOUTPUT_I_L;                                                \
    unsigned short EZOUTPUT_I_W = WIDTHS;                                      \
    unsigned char EZOUTPUT_I_C = COLUMNS;                                      \
    char *EZOUTPUT_I_Z = NULL;                                                 \
    char *EZOUTPUT_I_S = (char *)BUF;                                          \
    if ((NULL == EZOUTPUT_I_S) || (SIZE < 1)) {                                \
      if (NULL !=                                                              \
          (DISP = (char *)malloc(strlen(MODULE) + strlen("nothing@[]\n") +     \
                                 8 /* max length of address */ +               \
                                 5 /* max length of size */)))                 \
        sprintf(DISP, "%snothing@%p[%u]", MODULE, EZOUTPUT_I_S, SIZE);         \
      else                                                                     \
        DISP = NULL;                                                           \
    } else {                                                                   \
      if (SIZE > 65535 /* max of unsigned int (type of index) */) {            \
        if (NULL != (DISP = (char *)malloc(strlen(MODULE) +                    \
                                           strlen("[] too much to bear\n") +   \
                                           20 /* max length of size */)))      \
          sprintf(DISP, "%s[%e] too much to bear", MODULE, (double)SIZE);      \
        else                                                                   \
          DISP = NULL;                                                         \
      } else {                                                                 \
        EZOUTPUT_SUIT_WIDTH(EZOUTPUT_I_W, EZOUTPUT_I_C, BARRIER, OPTIONS);     \
        if ((0 != (OPTIONS % 2)) ||                                            \
            (NULL != (EZOUTPUT_I_Z =                                           \
                          (char *)calloc(1, sizeof(char) * EZOUTPUT_I_C)))) {  \
          if (NULL !=                                                          \
              (DISP = (char *)malloc(                                          \
                   strlen(MODULE) + strlen("@[]\n") +                          \
                   8 /* max length of address */ + 5 /* max length of size */  \
                   + (SIZE / EZOUTPUT_I_C + 1) *                               \
                         100 /* assume 100 characters per line*/))) {          \
            sprintf(DISP, "%s@%p[%u]", MODULE, EZOUTPUT_I_S, SIZE);            \
            for (EZOUTPUT_I_I = 0; EZOUTPUT_I_I < SIZE; EZOUTPUT_I_I++) {      \
              if (0 == EZOUTPUT_I_I % EZOUTPUT_I_C) {                          \
                if (0 == (OPTIONS % 2)) {                                      \
                  while (0 == memcmp(EZOUTPUT_I_Z,                             \
                                     &EZOUTPUT_I_S[EZOUTPUT_I_I],              \
                                     EZOUTPUT_I_C)) {                          \
                    EZOUTPUT_I_I += EZOUTPUT_I_C;                              \
                    if (EZOUTPUT_I_I >= SIZE) {                                \
                      EZOUTPUT_I_I = SIZE + 1;                                 \
                      break;                                                   \
                    }                                                          \
                  }                                                            \
                  if (EZOUTPUT_I_I > SIZE)                                     \
                    break;                                                     \
                }                                                              \
                sprintf(DISP + strlen(DISP), "\n%05d:",                        \
                        EZOUTPUT_I_I / EZOUTPUT_I_C * EZOUTPUT_I_C);           \
              } else if ((BARRIER > 0) &&                                      \
                         (0 == (EZOUTPUT_I_I % EZOUTPUT_I_C % BARRIER)))       \
                strcat(DISP, " |");                                            \
              EZOUTPUT_I_J = (unsigned char)EZOUTPUT_I_S[EZOUTPUT_I_I] / 0x10; \
              if (EZOUTPUT_I_J < 10)                                           \
                sprintf(DISP + strlen(DISP), " %d", EZOUTPUT_I_J);             \
              else                                                             \
                sprintf(DISP + strlen(DISP), " %c",                            \
                        EZOUTPUT_I_J + 48 - 10 + 17);                          \
              EZOUTPUT_I_J = (unsigned char)EZOUTPUT_I_S[EZOUTPUT_I_I] % 0x10; \
              if (EZOUTPUT_I_J < 10)                                           \
                sprintf(DISP + strlen(DISP), "%d", EZOUTPUT_I_J);              \
              else                                                             \
                sprintf(DISP + strlen(DISP), "%c",                             \
                        EZOUTPUT_I_J + 48 - 10 + 17);                          \
              if (((EZOUTPUT_I_C - 1) == (EZOUTPUT_I_I % EZOUTPUT_I_C)) ||     \
                  ((SIZE - 1) == EZOUTPUT_I_I)) {                              \
                strcat(DISP, " :");                                            \
                if (OPTIONS < 0) {                                             \
                  for (EZOUTPUT_I_J = EZOUTPUT_I_I % EZOUTPUT_I_C + 1;         \
                       EZOUTPUT_I_J > 0; EZOUTPUT_I_J--) {                     \
                    if ((BARRIER > 0) &&                                       \
                        (0 != ((EZOUTPUT_I_I - EZOUTPUT_I_J + 1) %             \
                               EZOUTPUT_I_C)) &&                               \
                        (0 == ((EZOUTPUT_I_I - EZOUTPUT_I_J + 1) %             \
                               EZOUTPUT_I_C % BARRIER)))                       \
                      strcat(DISP, " |");                                      \
                    strcat(DISP, " ");                                         \
                    EZOUTPUT_I_L =                                             \
                        EZOUTPUT_I_S[EZOUTPUT_I_I - EZOUTPUT_I_J + 1];         \
                    for (EZOUTPUT_I_K = 8; EZOUTPUT_I_K > 0; EZOUTPUT_I_K--) { \
                      if (EZOUTPUT_I_L >= (1 << (EZOUTPUT_I_K - 1))) {         \
                        EZOUTPUT_I_L -= (1 << (EZOUTPUT_I_K - 1));             \
                        strcat(DISP, "1");                                     \
                      } else                                                   \
                        strcat(DISP, "0");                                     \
                    }                                                          \
                  }                                                            \
                  strcat(DISP, " :");                                          \
                }                                                              \
                strcat(DISP, " ");                                             \
                for (EZOUTPUT_I_J = EZOUTPUT_I_I % EZOUTPUT_I_C + 1;           \
                     EZOUTPUT_I_J > 0;                                         \
                     EZOUTPUT_I_J--) { /* since EZOUTPUT_I_J is unsigned, we   \
                                          cannot set */                        \
                  /* EZOUTPUT_I_J to be one more than current */               \
                  if ((BARRIER > 0) &&                                         \
                      (0 !=                                                    \
                       ((EZOUTPUT_I_I - EZOUTPUT_I_J + 1) % EZOUTPUT_I_C)) &&  \
                      (0 == ((EZOUTPUT_I_I - EZOUTPUT_I_J + 1) %               \
                             EZOUTPUT_I_C % BARRIER)))                         \
                    strcat(DISP, " | ");                                       \
                  if ((EZOUTPUT_I_S[EZOUTPUT_I_I - EZOUTPUT_I_J + 1] > 32) &&  \
                      (EZOUTPUT_I_S[EZOUTPUT_I_I - EZOUTPUT_I_J + 1] < 126))   \
                    sprintf(DISP + strlen(DISP), "%c",                         \
                            EZOUTPUT_I_S[EZOUTPUT_I_I - EZOUTPUT_I_J + 1]);    \
                  else                                                         \
                    sprintf(DISP + strlen(DISP), "%c", 32);                    \
                }                                                              \
              }                                                                \
            }                                                                  \
            strcat(DISP, "\n");                                                \
          } else                                                               \
            DISP = NULL;                                                       \
          free(EZOUTPUT_I_Z);                                                  \
        }                                                                      \
      }                                                                        \
    }                                                                          \
  } while (0)

/*
DISP: char*, space allocated inside if successful
MODULE: char*, must not be NULL
BUF: char*, input memory address
SIZE: input memory size, 0-65535
WIDTHS: screen width. auto-shrink if larger than COLUMN
       0: unlimited
       if COLUMN not defined either, default to 80
COLUMNS: column(group) count in a line. auto-shrink if display result larger
than WIDTH 0: unlimited BARRIER: show | at every these columns. must not be 0
OPTIONS: signed integer(char, short, int or long)
       yes:  no:  functionality:
       odd  even  compress blank lines
       <0  >=0  display binary
*/
#define EZOUTPUT_D(DISP, MODULE, BUF, SIZE, WIDTHS, COLUMNS, BARRIER, OPTIONS) \
  do {                                                                         \
    unsigned int EZOUTPUT_D_I;                                                 \
    unsigned int EZOUTPUT_D_J;                                                 \
    unsigned int EZOUTPUT_D_K;                                                 \
    unsigned char EZOUTPUT_D_L;                                                \
    unsigned short EZOUTPUT_D_W = WIDTHS;                                      \
    unsigned char EZOUTPUT_D_C = COLUMNS;                                      \
    char *EZOUTPUT_D_Z = NULL;                                                 \
    char *EZOUTPUT_D_S = (char *)BUF;                                          \
    if ((NULL == EZOUTPUT_D_S) || (SIZE < 1)) {                                \
      printf("%s%s:%d %s nothing@%x[%u]\n", MODULE, __FILE__, __LINE__, INFO,  \
             EZOUTPUT_D_S, SIZE);                                              \
    } else {                                                                   \
      EZOUTPUT_SUIT_WIDTH(EZOUTPUT_D_W, EZOUTPUT_D_C, BARRIER, OPTIONS);       \
      if ((0 != (OPTIONS % 2)) ||                                              \
          (NULL !=                                                             \
           (EZOUTPUT_D_Z = (char *)calloc(1, sizeof(char) * EZOUTPUT_D_C)))) { \
        printf("%s%s:%d %s @%x[%u]", MODULE, __FILE__, __LINE__, INFO,         \
               EZOUTPUT_D_S, SIZE);                                            \
        for (EZOUTPUT_D_I = 0; EZOUTPUT_D_I < SIZE; EZOUTPUT_D_I++) {          \
          if (0 == EZOUTPUT_D_I % EZOUTPUT_D_C) {                              \
            if (0 == (OPTIONS % 2)) {                                          \
              while (0 == memcmp(EZOUTPUT_D_Z, &EZOUTPUT_D_S[EZOUTPUT_D_I],    \
                                 EZOUTPUT_D_C)) {                              \
                EZOUTPUT_D_I += EZOUTPUT_D_C;                                  \
                if (EZOUTPUT_D_I >= SIZE) {                                    \
                  EZOUTPUT_D_I = SIZE + 1;                                     \
                  break;                                                       \
                }                                                              \
              }                                                                \
              if (EZOUTPUT_D_I > SIZE)                                         \
                break;                                                         \
            }                                                                  \
            printf("\n%05d:", EZOUTPUT_D_I / EZOUTPUT_D_C * EZOUTPUT_D_C);     \
          } else if ((BARRIER > 0) &&                                          \
                     (0 == (EZOUTPUT_D_I % EZOUTPUT_D_C % BARRIER)))           \
            printf(" |");                                                      \
          EZOUTPUT_D_J = (unsigned char)EZOUTPUT_D_S[EZOUTPUT_D_I] / 0x10;     \
          if (EZOUTPUT_D_J < 10)                                               \
            printf(" %d", EZOUTPUT_D_J);                                       \
          else                                                                 \
            printf(" %c", EZOUTPUT_D_J + 48 - 10 + 17);                        \
          EZOUTPUT_D_J = (unsigned char)EZOUTPUT_D_S[EZOUTPUT_D_I] % 0x10;     \
          if (EZOUTPUT_D_J < 10)                                               \
            printf("%d", EZOUTPUT_D_J);                                        \
          else                                                                 \
            printf("%c", EZOUTPUT_D_J + 48 - 10 + 17);                         \
          if (((EZOUTPUT_D_C - 1) == (EZOUTPUT_D_I % EZOUTPUT_D_C)) ||         \
              ((SIZE - 1) == EZOUTPUT_D_I)) {                                  \
            printf(" :");                                                      \
            if (OPTIONS < 0) {                                                 \
              for (EZOUTPUT_D_J = EZOUTPUT_D_I % EZOUTPUT_D_C + 1;             \
                   EZOUTPUT_D_J > 0; EZOUTPUT_D_J--) {                         \
                if ((BARRIER > 0) &&                                           \
                    (0 !=                                                      \
                     ((EZOUTPUT_D_I - EZOUTPUT_D_J + 1) % EZOUTPUT_D_C)) &&    \
                    (0 == ((EZOUTPUT_D_I - EZOUTPUT_D_J + 1) % EZOUTPUT_D_C %  \
                           BARRIER)))                                          \
                  printf(" |");                                                \
                printf(" ");                                                   \
                EZOUTPUT_D_L = EZOUTPUT_D_S[EZOUTPUT_D_I - EZOUTPUT_D_J + 1];  \
                for (EZOUTPUT_D_K = 8; EZOUTPUT_D_K > 0; EZOUTPUT_D_K--) {     \
                  if (EZOUTPUT_D_L >= (1 << (EZOUTPUT_D_K - 1))) {             \
                    EZOUTPUT_D_L -= (1 << (EZOUTPUT_D_K - 1));                 \
                    printf("1");                                               \
                  } else                                                       \
                    printf("0");                                               \
                }                                                              \
              }                                                                \
              printf(" :");                                                    \
            }                                                                  \
            printf(" ");                                                       \
            for (EZOUTPUT_D_J = EZOUTPUT_D_I % EZOUTPUT_D_C + 1;               \
                 EZOUTPUT_D_J > 0; EZOUTPUT_D_J--) {                           \
              if ((BARRIER > 0) &&                                             \
                  (0 != ((EZOUTPUT_D_I - EZOUTPUT_D_J + 1) % EZOUTPUT_D_C)) && \
                  (0 == ((EZOUTPUT_D_I - EZOUTPUT_D_J + 1) % EZOUTPUT_D_C %    \
                         BARRIER)))                                            \
                printf(" | ");                                                 \
              if ((EZOUTPUT_D_S[EZOUTPUT_D_I - EZOUTPUT_D_J + 1] > 32) &&      \
                  (EZOUTPUT_D_S[EZOUTPUT_D_I - EZOUTPUT_D_J + 1] < 126))       \
                printf("%c", EZOUTPUT_D_S[EZOUTPUT_D_I - EZOUTPUT_D_J + 1]);   \
              else                                                             \
                printf("%c", 32);                                              \
            }                                                                  \
          }                                                                    \
        }                                                                      \
        printf("\n");                                                          \
        free(EZOUTPUT_D_Z);                                                    \
      }                                                                        \
    }                                                                          \
  } while (0)
